/*
 *  NFCSigning - Open source library for signing/validation of NDEF messages
 *  Copyright (C) 2009-2010 The NFCSigning Team
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 *
 */
package measure1;

import com.ericsson.nfc.signing.MessageValidator;
import com.ericsson.nfc.signing.Signature;
import com.ericsson.nfc.signing.SignedMessage;
import com.ericsson.nfc.signing.algorithm.DigestFactory;
import com.ericsson.nfc.signing.algorithm.ImplementationDetector;
import com.ericsson.nfc.signing.certificate.Certificate;
import com.ericsson.nfc.signing.certificate.CertificateChain;
import com.ericsson.nfc.signing.certificate.InvalidCertificateChain;
import com.ericsson.nfc.signing.certificate.X509Certificate;
import com.ericsson.nfc.signing.certificate.X509CertificateChain;
import com.ericsson.nfc.signing.record.URIRecord;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.Date;
import java.util.Random;
import javax.microedition.io.Connector;
import javax.microedition.io.file.FileConnection;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import org.bouncycastle.crypto.Digest;

//#if MyJSR257
//# import my.javax.microedition.contactless.ndef.NDEFMessage;
//# import my.javax.microedition.contactless.ndef.NDEFRecord;
//#else
import javax.microedition.contactless.ndef.NDEFMessage;
import javax.microedition.contactless.ndef.NDEFRecord;
//#endif

/**
 * @author emarkki
 */
public class MeasureVerificationTimeMIDlet extends MIDlet implements CommandListener {

    private boolean midletPaused = false;
    
    private PrintStream out = System.out;

    private Random sha1Random;
    
    private byte[] dataToHash = new byte[2048];
    
    private NDEFMessage msgSpUrlMinUser2SigDSA;
    private NDEFMessage msgSpUrlMinUser3SigECDSA;
    private NDEFMessage msgSpUrlMinUser1SigRSASSAPSS;
    private NDEFMessage msgSpUrlMinUser1SigRSAPKCS1;
    private NDEFMessage msgSpUrlAUser1;
    private NDEFMessage msgSpUrlAUser2;
    private NDEFMessage msgSpUrlAUser3;
    private NDEFMessage msgSpUrlAUser4;
    private NDEFMessage msgSpUrlBUser1;
    private NDEFMessage msgSpUrlBUser2;
    private NDEFMessage msgSpUrlCUser1;
    private NDEFMessage msgSpUrlDUser1;
    private NDEFMessage msgSpUrlDUser2;
    private NDEFMessage msgSpUrlDUser3;
    private NDEFMessage msgSpUrlDUser4;
    
    Certificate[] trustedCerts;
    
    //<editor-fold defaultstate="collapsed" desc=" Generated Fields ">//GEN-BEGIN:|fields|0|
    private Form form;
    private ChoiceGroup choiceGroupRun;
    private TextField textFieldIterations;
    private ChoiceGroup choiceGroup;
    private Command exitCommand;
    private Command okCommand;
    private Command dumpFileCommand;
    //</editor-fold>//GEN-END:|fields|0|
    
    /**
     * The MeasureVerificationTimeMIDlet constructor.
     */
    public MeasureVerificationTimeMIDlet() {
    }

    private void dumpFileCommandPerformed() {
        FileConnection conn = null;
        try {
            String fileName = System.getProperty("fileconn.dir.photos") + "verifytime.log";
            conn = (FileConnection) Connector.open(fileName, Connector.READ);
            if (!conn.exists()) {
                getDisplay().setCurrent(new Alert("No such file"));
                return;
            }
            
            InputStream in = conn.openDataInputStream();
            String s;
            int ch;
            while((ch = in.read()) != -1) {
                System.out.print((char)ch);
            }
            
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            if(conn != null) {
                try {
                    conn.close();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        }
    }

    private void initMeasurements() {
        try {

            if (choiceGroupRun.isSelected(0)) {
            }
            if (choiceGroupRun.isSelected(1)) {
            }
            if (choiceGroupRun.isSelected(2)) {
                try {
                    msgSpUrlMinUser2SigDSA = new NDEFMessage(Data.readBinaryFile(Data.msgSpUrlMinUser2SigDSA), 0);
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
            if (choiceGroupRun.isSelected(3)) {
                try {
                    msgSpUrlMinUser3SigECDSA = new NDEFMessage(Data.readBinaryFile(Data.msgSpUrlMinUser3SigECDSA), 0);
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
            if (choiceGroupRun.isSelected(4)) {
                msgSpUrlMinUser1SigRSASSAPSS = new NDEFMessage(Data.readBinaryFile(Data.msgSpUrlMinUser1SigRSASSAPSS), 0);
            }
            if (choiceGroupRun.isSelected(5)) {
                msgSpUrlMinUser1SigRSAPKCS1 = new NDEFMessage(Data.readBinaryFile(Data.msgSpUrlMinUser1SigRSAPKCS1), 0);
            }
            if (choiceGroupRun.isSelected(6)) {
                Random rand = new Random(0x987654);
                for(int i = 0; i < dataToHash.length; i++) {
                    dataToHash[i] = (byte)rand.nextInt(256);
                }
            }
            if (choiceGroupRun.isSelected(7)) { // Certificate: DSA
            }
            if (choiceGroupRun.isSelected(8)) { // Certificate: ECDSA
            }
            if (choiceGroupRun.isSelected(9)) { // Certificate: RSA
            }
            if (choiceGroupRun.isSelected(10)) { // SHA-1 random
            }

            if (choiceGroupRun.isSelected(11)) {
                msgSpUrlAUser1 = new NDEFMessage(Data.readBinaryFile(Data.msgSpUrlAUser1), 0);
            }
            if (choiceGroupRun.isSelected(12)) {
                msgSpUrlAUser2 = new NDEFMessage(Data.readBinaryFile(Data.msgSpUrlAUser2), 0);
            }
            if (choiceGroupRun.isSelected(13)) {
                msgSpUrlAUser3 = new NDEFMessage(Data.readBinaryFile(Data.msgSpUrlAUser3), 0);
            }
            if (choiceGroupRun.isSelected(14)) {
                msgSpUrlAUser4 = new NDEFMessage(Data.readBinaryFile(Data.msgSpUrlAUser4), 0);
            }
            if (choiceGroupRun.isSelected(15)) {
                msgSpUrlBUser1 = new NDEFMessage(Data.readBinaryFile(Data.msgSpUrlBUser1), 0);
            }
            if (choiceGroupRun.isSelected(16)) {
                msgSpUrlBUser2 = new NDEFMessage(Data.readBinaryFile(Data.msgSpUrlBUser2), 0);
            }
            if (choiceGroupRun.isSelected(17)) {
                msgSpUrlCUser1 = new NDEFMessage(Data.readBinaryFile(Data.msgSpUrlCUser1), 0);
            }
            if (choiceGroupRun.isSelected(18)) {
                msgSpUrlDUser1 = new NDEFMessage(Data.readBinaryFile(Data.msgSpUrlDUser1), 0);
            }
            if (choiceGroupRun.isSelected(19)) {
                msgSpUrlDUser2 = new NDEFMessage(Data.readBinaryFile(Data.msgSpUrlDUser2), 0);
            }
            if (choiceGroupRun.isSelected(20)) {
                msgSpUrlDUser3 = new NDEFMessage(Data.readBinaryFile(Data.msgSpUrlDUser3), 0);
            }
            if (choiceGroupRun.isSelected(21)) {
                msgSpUrlDUser4 = new NDEFMessage(Data.readBinaryFile(Data.msgSpUrlDUser4), 0);
            }
            
            try {
                trustedCerts = new Certificate[]{
                    new X509Certificate(getClass().getResourceAsStream("files/a-root-ca.cer")),
                    new X509Certificate(getClass().getResourceAsStream("files/b-root-ca.cer")),
                    new X509Certificate(getClass().getResourceAsStream("files/c-root-ca.cer")),
                    new X509Certificate(getClass().getResourceAsStream("files/d-root-ca.cer")),
                    new X509Certificate(getClass().getResourceAsStream("files/NordicRootCA.cer")),
                    new X509Certificate(getClass().getResourceAsStream("files/SwedenRootCA.cer")),
                    new X509Certificate(getClass().getResourceAsStream("files/SwissRootCA.cer")),
                    new X509Certificate(getClass().getResourceAsStream("files/ScandinaviaRootCA.cer"))
                };
            } catch (IOException ex) {
                ex.printStackTrace();
            }

            
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
    

    //<editor-fold defaultstate="collapsed" desc=" Generated Methods ">//GEN-BEGIN:|methods|0|
    //</editor-fold>//GEN-END:|methods|0|

    //<editor-fold defaultstate="collapsed" desc=" Generated Method: initialize ">//GEN-BEGIN:|0-initialize|0|0-preInitialize
    /**
     * Initilizes the application.
     * It is called only once when the MIDlet is started. The method is called before the <code>startMIDlet</code> method.
     */
    private void initialize() {//GEN-END:|0-initialize|0|0-preInitialize
        // write pre-initialize user code here
//GEN-LINE:|0-initialize|1|0-postInitialize
        // write post-initialize user code here
    }//GEN-BEGIN:|0-initialize|2|
    //</editor-fold>//GEN-END:|0-initialize|2|

    //<editor-fold defaultstate="collapsed" desc=" Generated Method: startMIDlet ">//GEN-BEGIN:|3-startMIDlet|0|3-preAction
    /**
     * Performs an action assigned to the Mobile Device - MIDlet Started point.
     */
    public void startMIDlet() {//GEN-END:|3-startMIDlet|0|3-preAction
        // write pre-action user code here
        switchDisplayable(null, getForm());//GEN-LINE:|3-startMIDlet|1|3-postAction
        // write post-action user code here
    }//GEN-BEGIN:|3-startMIDlet|2|
    //</editor-fold>//GEN-END:|3-startMIDlet|2|

    //<editor-fold defaultstate="collapsed" desc=" Generated Method: resumeMIDlet ">//GEN-BEGIN:|4-resumeMIDlet|0|4-preAction
    /**
     * Performs an action assigned to the Mobile Device - MIDlet Resumed point.
     */
    public void resumeMIDlet() {//GEN-END:|4-resumeMIDlet|0|4-preAction
        // write pre-action user code here
//GEN-LINE:|4-resumeMIDlet|1|4-postAction
        // write post-action user code here
    }//GEN-BEGIN:|4-resumeMIDlet|2|
    //</editor-fold>//GEN-END:|4-resumeMIDlet|2|

    //<editor-fold defaultstate="collapsed" desc=" Generated Method: switchDisplayable ">//GEN-BEGIN:|5-switchDisplayable|0|5-preSwitch
    /**
     * Switches a current displayable in a display. The <code>display</code> instance is taken from <code>getDisplay</code> method. This method is used by all actions in the design for switching displayable.
     * @param alert the Alert which is temporarily set to the display; if <code>null</code>, then <code>nextDisplayable</code> is set immediately
     * @param nextDisplayable the Displayable to be set
     */
    public void switchDisplayable(Alert alert, Displayable nextDisplayable) {//GEN-END:|5-switchDisplayable|0|5-preSwitch
        // write pre-switch user code here
        Display display = getDisplay();//GEN-BEGIN:|5-switchDisplayable|1|5-postSwitch
        if (alert == null) {
            display.setCurrent(nextDisplayable);
        } else {
            display.setCurrent(alert, nextDisplayable);
        }//GEN-END:|5-switchDisplayable|1|5-postSwitch
        // write post-switch user code here
    }//GEN-BEGIN:|5-switchDisplayable|2|
    //</editor-fold>//GEN-END:|5-switchDisplayable|2|

    //<editor-fold defaultstate="collapsed" desc=" Generated Method: commandAction for Displayables ">//GEN-BEGIN:|7-commandAction|0|7-preCommandAction
    /**
     * Called by a system to indicated that a command has been invoked on a particular displayable.
     * @param command the Command that was invoked
     * @param displayable the Displayable where the command was invoked
     */
    public void commandAction(Command command, Displayable displayable) {//GEN-END:|7-commandAction|0|7-preCommandAction
 // write pre-action user code here
        if (displayable == form) {//GEN-BEGIN:|7-commandAction|1|38-preAction
            if (command == dumpFileCommand) {//GEN-END:|7-commandAction|1|38-preAction
 // write pre-action user code here
    dumpFileCommandPerformed();
//GEN-LINE:|7-commandAction|2|38-postAction
 // write post-action user code here
            } else if (command == exitCommand) {//GEN-LINE:|7-commandAction|3|16-preAction
 // write pre-action user code here
                exitMIDlet();//GEN-LINE:|7-commandAction|4|16-postAction
 // write post-action user code here
            } else if (command == okCommand) {//GEN-LINE:|7-commandAction|5|19-preAction
 // write pre-action user code here
//GEN-LINE:|7-commandAction|6|19-postAction
 // write post-action user code here
    startMeasurements();
            }//GEN-BEGIN:|7-commandAction|7|7-postCommandAction
        }//GEN-END:|7-commandAction|7|7-postCommandAction
 // write post-action user code here
    }//GEN-BEGIN:|7-commandAction|8|
    //</editor-fold>//GEN-END:|7-commandAction|8|

    //<editor-fold defaultstate="collapsed" desc=" Generated Getter: form ">//GEN-BEGIN:|13-getter|0|13-preInit
    /**
     * Returns an initiliazed instance of form component.
     * @return the initialized component instance
     */
    public Form getForm() {
        if (form == null) {//GEN-END:|13-getter|0|13-preInit
 // write pre-init user code here
            form = new Form("form", new Item[] { getChoiceGroupRun(), getTextFieldIterations(), getChoiceGroup() });//GEN-BEGIN:|13-getter|1|13-postInit
            form.addCommand(getExitCommand());
            form.addCommand(getOkCommand());
            form.addCommand(getDumpFileCommand());
            form.setCommandListener(this);//GEN-END:|13-getter|1|13-postInit
 // write post-init user code here
        }//GEN-BEGIN:|13-getter|2|
        return form;
    }
    //</editor-fold>//GEN-END:|13-getter|2|

    //<editor-fold defaultstate="collapsed" desc=" Generated Getter: exitCommand ">//GEN-BEGIN:|15-getter|0|15-preInit
    /**
     * Returns an initiliazed instance of exitCommand component.
     * @return the initialized component instance
     */
    public Command getExitCommand() {
        if (exitCommand == null) {//GEN-END:|15-getter|0|15-preInit
 // write pre-init user code here
            exitCommand = new Command("Exit", Command.EXIT, 0);//GEN-LINE:|15-getter|1|15-postInit
 // write post-init user code here
        }//GEN-BEGIN:|15-getter|2|
        return exitCommand;
    }
    //</editor-fold>//GEN-END:|15-getter|2|

    //<editor-fold defaultstate="collapsed" desc=" Generated Getter: okCommand ">//GEN-BEGIN:|18-getter|0|18-preInit
    /**
     * Returns an initiliazed instance of okCommand component.
     * @return the initialized component instance
     */
    public Command getOkCommand() {
        if (okCommand == null) {//GEN-END:|18-getter|0|18-preInit
 // write pre-init user code here
            okCommand = new Command("Start", Command.OK, 0);//GEN-LINE:|18-getter|1|18-postInit
 // write post-init user code here
        }//GEN-BEGIN:|18-getter|2|
        return okCommand;
    }
    //</editor-fold>//GEN-END:|18-getter|2|

    //<editor-fold defaultstate="collapsed" desc=" Generated Getter: textFieldIterations ">//GEN-BEGIN:|20-getter|0|20-preInit
    /**
     * Returns an initiliazed instance of textFieldIterations component.
     * @return the initialized component instance
     */
    public TextField getTextFieldIterations() {
        if (textFieldIterations == null) {//GEN-END:|20-getter|0|20-preInit
 // write pre-init user code here
            textFieldIterations = new TextField("Iterations for each:", "10", 32, TextField.NUMERIC);//GEN-LINE:|20-getter|1|20-postInit
 // write post-init user code here
        }//GEN-BEGIN:|20-getter|2|
        return textFieldIterations;
    }
    //</editor-fold>//GEN-END:|20-getter|2|

    //<editor-fold defaultstate="collapsed" desc=" Generated Getter: choiceGroupRun ">//GEN-BEGIN:|21-getter|0|21-preInit
    /**
     * Returns an initiliazed instance of choiceGroupRun component.
     * @return the initialized component instance
     */
    public ChoiceGroup getChoiceGroupRun() {
        if (choiceGroupRun == null) {//GEN-END:|21-getter|0|21-preInit
 // write pre-init user code here
            choiceGroupRun = new ChoiceGroup("Run:", Choice.MULTIPLE);//GEN-BEGIN:|21-getter|1|21-postInit
            choiceGroupRun.append("Empty/null test", null);
            choiceGroupRun.append("Empty/null test (aggregated)", null);
            choiceGroupRun.append("Verify 1 - DSA", null);
            choiceGroupRun.append("Verify 2 - ECDSA", null);
            choiceGroupRun.append("Verify 3 - RSASSA-PSS", null);
            choiceGroupRun.append("Verify 4 - RSASSA-PKCS1", null);
            choiceGroupRun.append("SHA-1", null);
            choiceGroupRun.append("Certificate: DSA", null);
            choiceGroupRun.append("Certificate: ECDSA", null);
            choiceGroupRun.append("Certificate: RSA", null);
            choiceGroupRun.append("SHA-1 random", null);
            choiceGroupRun.append("A User1", null);
            choiceGroupRun.append("A User2", null);
            choiceGroupRun.append("A User3", null);
            choiceGroupRun.append("A User4", null);
            choiceGroupRun.append("B User1", null);
            choiceGroupRun.append("B User2", null);
            choiceGroupRun.append("C User1", null);
            choiceGroupRun.append("D User1", null);
            choiceGroupRun.append("D User2", null);
            choiceGroupRun.append("D User3", null);
            choiceGroupRun.append("D User4", null);
            choiceGroupRun.setSelectedFlags(new boolean[] { false, false, false, false, false, false, true, true, true, true, true, true, false, true, false, true, false, true, true, true, false, true });
            choiceGroupRun.setFont(0, null);
            choiceGroupRun.setFont(1, null);
            choiceGroupRun.setFont(2, null);
            choiceGroupRun.setFont(3, null);
            choiceGroupRun.setFont(4, null);
            choiceGroupRun.setFont(5, null);
            choiceGroupRun.setFont(6, null);
            choiceGroupRun.setFont(7, null);
            choiceGroupRun.setFont(8, null);
            choiceGroupRun.setFont(9, null);
            choiceGroupRun.setFont(10, null);
            choiceGroupRun.setFont(11, null);
            choiceGroupRun.setFont(12, null);
            choiceGroupRun.setFont(13, null);
            choiceGroupRun.setFont(14, null);
            choiceGroupRun.setFont(15, null);
            choiceGroupRun.setFont(16, null);
            choiceGroupRun.setFont(17, null);
            choiceGroupRun.setFont(18, null);
            choiceGroupRun.setFont(19, null);
            choiceGroupRun.setFont(20, null);
            choiceGroupRun.setFont(21, null);//GEN-END:|21-getter|1|21-postInit
 // write post-init user code here
        }//GEN-BEGIN:|21-getter|2|
        return choiceGroupRun;
    }
    //</editor-fold>//GEN-END:|21-getter|2|

    //<editor-fold defaultstate="collapsed" desc=" Generated Getter: choiceGroup ">//GEN-BEGIN:|29-getter|0|29-preInit
    /**
     * Returns an initiliazed instance of choiceGroup component.
     * @return the initialized component instance
     */
    public ChoiceGroup getChoiceGroup() {
        if (choiceGroup == null) {//GEN-END:|29-getter|0|29-preInit
 // write pre-init user code here
            choiceGroup = new ChoiceGroup("Output results:", Choice.EXCLUSIVE);//GEN-BEGIN:|29-getter|1|29-postInit
            choiceGroup.append("System.out", null);
            choiceGroup.append("Log-file: C:\\verifytime.log", null);
            choiceGroup.setSelectedFlags(new boolean[] { false, false });
            choiceGroup.setFont(0, null);
            choiceGroup.setFont(1, null);//GEN-END:|29-getter|1|29-postInit
 // write post-init user code here
        }//GEN-BEGIN:|29-getter|2|
        return choiceGroup;
    }
    //</editor-fold>//GEN-END:|29-getter|2|

    //<editor-fold defaultstate="collapsed" desc=" Generated Getter: dumpFileCommand ">//GEN-BEGIN:|37-getter|0|37-preInit
    /**
     * Returns an initiliazed instance of dumpFileCommand component.
     * @return the initialized component instance
     */
    public Command getDumpFileCommand() {
        if (dumpFileCommand == null) {//GEN-END:|37-getter|0|37-preInit
 // write pre-init user code here
            dumpFileCommand = new Command("Dump file", Command.ITEM, 0);//GEN-LINE:|37-getter|1|37-postInit
 // write post-init user code here
        }//GEN-BEGIN:|37-getter|2|
        return dumpFileCommand;
    }
    //</editor-fold>//GEN-END:|37-getter|2|

    /**
     * Returns a display instance.
     * @return the display instance.
     */
    public Display getDisplay () {
        return Display.getDisplay(this);
    }

    /**
     * Exits MIDlet.
     */
    public void exitMIDlet() {
        switchDisplayable (null, null);
        destroyApp(true);
        notifyDestroyed();
    }

    /**
     * Called when MIDlet is started.
     * Checks whether the MIDlet have been already started and initialize/starts or resumes the MIDlet.
     */
    public void startApp() {
        if (midletPaused) {
            resumeMIDlet ();
        } else {
            initialize ();
            startMIDlet ();
        }
        midletPaused = false;
    }

    /**
     * Called when MIDlet is paused.
     */
    public void pauseApp() {
        midletPaused = true;
    }

    /**
     * Called to signal the MIDlet to terminate.
     * @param unconditional if true, then the MIDlet has to be unconditionally terminated and all resources has to be released.
     */
    public void destroyApp(boolean unconditional) {
    }

//    private boolean sha1() {
//        Digest d = DigestFactory.getDigest("SHA-1");
//        byte[] result = new byte[d.getDigestSize()];
//        d.update(Data.certToDigest, 0, Data.certToDigest.length);
//        d.doFinal(result, 0);
//        return Utils.equals(Data.certToDigestSHA1, result);
//    }
    
    private boolean sha1() {
        Digest d = DigestFactory.getDigest("SHA-1");
//            System.out.println("d:"+d);
        byte[] result = new byte[d.getDigestSize()];
        byte[] data = Data.certToDigest;
        d.update(data, 0, data.length);
        d.doFinal(result, 0);
//            System.out.println("Expected: " + Utils.toFixedHexString(Data.certToDigestSHA1));
//            System.out.println("Actuall: " + Utils.toFixedHexString(result));
        return Utils.equals(Data.certToDigestSHA1, result);
    }
    
    private boolean sha1Random(int numBytes) {
        
        Digest d = DigestFactory.getDigest("SHA-1");
        byte[] result = new byte[d.getDigestSize()];
        d.update(dataToHash, 0, numBytes);
        d.doFinal(result, 0);
        
        return true;
    }

    private void startMeasurements() {
        
        FileConnection conn = null;
        
        try {
        
            if(choiceGroup.isSelected(1)) {
            
                String fileName = System.getProperty("fileconn.dir.photos")+"verifytime.log";
                System.out.println("Openning " + fileName);
                
                conn = (FileConnection) Connector.open(fileName, Connector.READ_WRITE);
                
//                if(!conn.exists()) {
//                    getDisplay().setCurrent(new Alert("no image folder"), getForm());
//                    return;
//                }
//                
//                StringBuffer sb = new StringBuffer();
//                for(Enumeration e = conn.list(); e.hasMoreElements();) {
//                    sb.append(e.nextElement());
//                    sb.append("\n");
//                }
//                getDisplay().setCurrent(new Alert("files:", sb.toString(), null, AlertType.INFO), getForm());
//                
//                conn.
//                
//                return;
                
                if(!conn.exists()) {
                    conn.create();
                } else {
                    conn.truncate(0);
                }
                out = new PrintStream(conn.openOutputStream());                
            }
        
        out.println();
        out.println();
        out.println(new Date());
        
        out.println("         \titeration\ttest\ttime");
        
        int numIterations = Integer.parseInt(textFieldIterations.getString());
        out.println("Iterations: " + numIterations);
        
        // Init data
        initMeasurements();
        
        
        final long sha1RandomSeed = 0x123456;
        sha1Random = new Random(sha1RandomSeed);
        
        runMeasurements(numIterations);

//        sha1Random.setSeed(sha1RandomSeed);
        
        // If SATSA is available, also run without it
//        if(ImplementationDetector.getInstance().isSatsaAvailable()) {
//            ImplementationDetector.getInstance().setUseSatsa(false);
//            runMeasurements(numIterations, ImplementationDetector.getInstance().isSatsaAvailable());
//        }
        
        out.println("DONE");
        out.flush();
        System.out.println("DONE");
        
        Alert finished = new Alert("Done", "Test finished", null, AlertType.INFO);
        finished.setTimeout(Alert.FOREVER);
        getDisplay().setCurrent(finished);
        
        } catch (IOException ex) {
            ex.printStackTrace();
            getDisplay().setCurrent(new Alert("IOException", ex.getMessage(), null, AlertType.ERROR), getForm());
        } catch (SecurityException ex) {
            ex.printStackTrace();
            getDisplay().setCurrent(new Alert("SecurityException", ex.getMessage(), null, AlertType.ERROR), getForm());
        } finally {
            
            if(out != System.out) {
                out.close();
            }
            
            if(conn != null) {
                try {
                    conn.close();
                } catch (IOException ex) {
                    ex.printStackTrace();
                    getDisplay().setCurrent(new Alert("IOException", ex.getMessage(), null, AlertType.ERROR), getForm());
                }
            }
        }
        
    }
    
    private void runMeasurements(int numIterations) {
        
        ImplementationDetector.getInstance().setUseSatsa(true);
        boolean satsaSupported = ImplementationDetector.getInstance().isSatsaAvailable();
        
        boolean useSatsa = satsaSupported;
        
        int printCounter = 0;
        
        for(int iteration = 0; iteration < numIterations; iteration++,printCounter++) {
           
            if(printCounter >= 10) {
                printCounter = 0;
                System.out.println(iteration);
            }
            
            boolean result = true;
            long time;
            
            // Init random data for this iteration
            int numBytes = sha1Random.nextInt(dataToHash.length);

            // Run all tests
            for(int test = 0; test < choiceGroupRun.size(); test++) {

                if(!choiceGroupRun.isSelected(test)) {
                    continue;
                }
                
                long timeStart;
                
                
                // Run both with and without satsa if supported
                for(int s = 0; s < 2; s++) {

                    switch(test) {
                       case 0: {
                            timeStart = System.currentTimeMillis();
                            emptyMethod();
                            time = System.currentTimeMillis() - timeStart;
                            break;
                        }
                        case 1: {
                            timeStart = System.currentTimeMillis();
                            for(int i = 0; i < 1000000; i++) {
                                emptyMethod();
                            }
                            time = (System.currentTimeMillis() - timeStart);
                            break;
                        }
                        case 2: {
                            timeStart = System.currentTimeMillis();
                            result = recordDetected(msgSpUrlMinUser2SigDSA, "http://www.ericsson.com", "C=SE,CN=Minimum User 2");
                            time = System.currentTimeMillis() - timeStart;
                            break;
                        }
                        case 3: {
                            timeStart = System.currentTimeMillis();
                            result = recordDetected(msgSpUrlMinUser3SigECDSA, "http://www.ericsson.com", "C=SE,CN=Minimum User 3");
                            time = System.currentTimeMillis() - timeStart;
                            break;
                        }
                        case 4: {
                            timeStart = System.currentTimeMillis();
                            result = recordDetected(msgSpUrlMinUser1SigRSASSAPSS, "http://www.ericsson.com", "C=SE,CN=Minimum User 1");
                            time = System.currentTimeMillis() - timeStart;
                            break;
                        }
                        case 5: {
                            timeStart = System.currentTimeMillis();
                            result = recordDetected(msgSpUrlMinUser1SigRSAPKCS1, "http://www.ericsson.com", "C=SE,CN=Minimum User 1");
                            time = System.currentTimeMillis() - timeStart;
                            break;
                        }
                        case 6: {
                            timeStart = System.currentTimeMillis();
                            result = sha1();
                            time = System.currentTimeMillis() - timeStart;
                            break;
                        }
                        case 7: { // Certificate: DSA
                            timeStart = System.currentTimeMillis();
                            result = verifyCert(Data.certScandinaviaRootCA);
                            time = System.currentTimeMillis() - timeStart;
                            break;
                        }
                        case 8: { // Certificate: ECDSA
                            timeStart = System.currentTimeMillis();
                            result = verifyCert(Data.certSwissRootCA);
                            time = System.currentTimeMillis() - timeStart;
                            break;
                        }
                        case 9: { // Certificate: RSA
                            timeStart = System.currentTimeMillis();
                            result = verifyCert(Data.certNordiRootCA);
                            time = System.currentTimeMillis() - timeStart;
                            break;
                        }
                        case 10: { // SHA-1 random
                            timeStart = System.currentTimeMillis();
                            result = sha1Random(numBytes);
                            time = System.currentTimeMillis() - timeStart;
                            break;
                        }
                        case 11: {
                            timeStart = System.currentTimeMillis();
                            result = recordDetected(msgSpUrlAUser1, "http://www.ericsson.com", "C=SE,CN=A User1");
                            time = System.currentTimeMillis() - timeStart;
                            break;
                        }
                        case 12: {
                            timeStart = System.currentTimeMillis();
                            result = recordDetected(msgSpUrlAUser2, "http://www.ericsson.com", "C=SE,CN=A User2");
                            time = System.currentTimeMillis() - timeStart;
                            break;
                        }
                        case 13: {
                            timeStart = System.currentTimeMillis();
                            result = recordDetected(msgSpUrlAUser3, "http://www.ericsson.com", "C=SE,CN=A User3");
                            time = System.currentTimeMillis() - timeStart;
                            break;
                        }
                        case 14: {
                            timeStart = System.currentTimeMillis();
                            result = recordDetected(msgSpUrlAUser4, "http://www.ericsson.com", "C=SE,CN=A User4");
                            time = System.currentTimeMillis() - timeStart;
                            break;
                        }
                        case 15: {
                            timeStart = System.currentTimeMillis();
                            result = recordDetected(msgSpUrlBUser1, "http://www.ericsson.com", "CN=B User1,C=SE");
                            time = System.currentTimeMillis() - timeStart;
                            break;
                        }
                        case 16: {
                            timeStart = System.currentTimeMillis();
                            result = recordDetected(msgSpUrlBUser2, "http://www.ericsson.com", "CN=B User2,C=SE");
                            time = System.currentTimeMillis() - timeStart;
                            break;
                        }
                        case 17: {
                            timeStart = System.currentTimeMillis();
                            result = recordDetected(msgSpUrlCUser1, "http://www.ericsson.com", "C=SE,CN=C User1");
                            time = System.currentTimeMillis() - timeStart;
                            break;
                        }
                        case 18: {
                            timeStart = System.currentTimeMillis();
                            result = recordDetected(msgSpUrlDUser1, "http://www.ericsson.com", "C=SE,CN=D User1");
                            time = System.currentTimeMillis() - timeStart;
                            break;
                        }
                        case 19: {
                            timeStart = System.currentTimeMillis();
                            result = recordDetected(msgSpUrlDUser2, "http://www.ericsson.com", "C=SE,CN=D User2");
                            time = System.currentTimeMillis() - timeStart;
                            break;
                        }
                        case 20: {
                            timeStart = System.currentTimeMillis();
                            result = recordDetected(msgSpUrlDUser3, "http://www.ericsson.com", "C=SE,CN=D User3");
                            time = System.currentTimeMillis() - timeStart;
                            break;
                        }
                        case 21: {
                            timeStart = System.currentTimeMillis();
                            result = recordDetected(msgSpUrlDUser4, "http://www.ericsson.com", "C=SE,CN=D User4");
                            time = System.currentTimeMillis() - timeStart;
                            break;
                        }
                        default: {
                            System.err.println("No such test");
                            return;
                        }
                    }

                    out.println("--Result:\t" + iteration + "\t" + test + "\t"+time + "\t" + useSatsa + "\t" + (!result ? "FAILED" : "OK") + (test==10 ? "\t"+numBytes : ""));
                    
                    if(!satsaSupported) {
                        break;
                    }
                    useSatsa = !useSatsa;
                    ImplementationDetector.getInstance().setUseSatsa(useSatsa);
                    
                }
            }
            
            out.flush();
        }
    }
    
    public void emptyMethod() {}

    public boolean recordDetected(NDEFMessage msg, String expectedUri, String expectedFrom) {
        
        NDEFRecord r = msg.getRecord(0);

        if (r == null) {
            getForm().append("No SmartPoster found.\n");
            return false;
        }

        NDEFMessage sp = r.getNestedNDEFMessage(0);

        int interestingIndex = 0;
//        Certificate[] trustedCerts;

        

        MessageValidator validatorInfo = new MessageValidator(trustedCerts, null, null);
        SignedMessage results = validatorInfo.validate(r.getNestedNDEFMessage(0), new int[]{interestingIndex});
        Signature signature = results.getRecordsSignature(interestingIndex);

        URIRecord uri = new URIRecord(sp.getRecords()[interestingIndex].getPayload(), 0);
//        System.out.println("URI: " + uri.getURI());
        String sUri = uri.getURI();
        
        if(!expectedUri.equals(sUri)) {
            return false;
        }

        if(signature == null) {
            out.println("Warning: Invalid signature");
            return false;
        } else if(!signature.getStatus().isValid()) {
            out.println("Warning: Invalid signature, " + signature.getStatus().getErrorMessage());
            return false;
        } else {
//            System.out.println("Valid signature");
            if(signature.getStatus().getCertificateChain().getUserCertificate() instanceof X509Certificate) {
                String from = ((X509Certificate)signature.getStatus().getCertificateChain().getUserCertificate()).getStructure().getSubject().toString();
//                System.out.println("from " + from);

//                final X509CertificateChain chain = (X509CertificateChain) signature.getStatus().getCertificateChain();
                
                return expectedFrom.equals(from);
            }
            return false;
        }
    }

    private boolean verifyCert(String certFilePath) {
        try {
            X509Certificate cert = new X509Certificate(getClass().getResourceAsStream(certFilePath));
            CertificateChain chain = new X509CertificateChain(new X509Certificate[]{cert});
            return chain.validateChain(new Certificate[]{cert});
        } catch (InvalidCertificateChain ex) {
            ex.printStackTrace();
            return false;
        } catch (IOException ex) {
            ex.printStackTrace();
            return false;
        }
    }
}
